package com.itheima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.itheima.admin.feign.AdChannelFeign;
import com.itheima.admin.pojo.AdChannel;
import com.itheima.common.constants.SystemConstants;
import com.itheima.common.exception.LeadNewsException;
import com.itheima.common.vo.ResultVo;
import com.itheima.wemedia.service.ApiService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class ApiServiceImpl implements ApiService {

    @Autowired
    private AdChannelFeign adChannelFeign;
    /**
     * stringRedisTemplate: key与value的序列化器都使用的是字符串, stringRedisTemplate是RedisTemplate子类
     *                      json{}  {name:asdf}
     * RedisTemplate: key与value序列化器使用默认的jdk序列化方式(ObjectOutputStream) 字节数组
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 频道列表查询 优先查询redis，没有再远程调用admin微服查询
     *
     * 延迟双删
     *
     * 删除redis()
     * 删除数据库()master  mysql主从同步   查询slave
     * delay(500)
     * 删除redis() 保证更新成功后，一定时最新的
     *
     * @return
     */
    @Override
    public List<AdChannel> channelList() {
        //1. 定义key
        String key = SystemConstants.REDISKEY_CHANNELLIST;
        //2. 从redis来读取数据
        String channelListInRedis = stringRedisTemplate.opsForValue().get(key);
        List<AdChannel> channelList = new ArrayList<>();
        //3. 有数据
        if(!StringUtils.isEmpty(channelListInRedis)) {
            //  3.1 解析json字符串转成list
            channelList = JSON.parseArray(channelListInRedis, AdChannel.class);
        }else {
            //4. 没数据
            //4.1 远程调用admin微服，查询list
            ResultVo<List<AdChannel>> listResultVo = adChannelFeign.getChannelList();
            //4.2 解析结果,
            if(!listResultVo.isSuccess()){
                log.error("远程调用admin微服查询频道列表失败:{}",listResultVo.getErrorMessage());
                throw new LeadNewsException("查询频道列表失败!");
            }
            // 有数据, 转成json字符串 存入redis
            channelList = listResultVo.getData();
            // 防止缓存穿透, 即使没有数据，也要存入redis,设置短暂有效期
            if(CollectionUtils.isEmpty(channelList)){
                stringRedisTemplate.opsForValue().set(key,null,15, TimeUnit.SECONDS);
            }else{
                String jsonString = JSON.toJSONString(channelList);
                stringRedisTemplate.opsForValue().set(key,jsonString);
            }
        }
        //5. 返回list
        return channelList;
    }
}
